
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
// 
//   http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
// 
//   http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
import * as layout from '../../util/layout.js';
import { parsePercent, linearMap } from '../../util/number.js';
import { isFunction } from 'zrender/lib/core/util.js';

function getViewRect(seriesModel, api) {
	return layout.getLayoutRect(seriesModel.getBoxLayoutParams(), {
		width: api.getWidth(),
		height: api.getHeight()
	});
}

function getSortedIndices(data, sort) {
	var valueDim = data.mapDimension('value');
	var valueArr = data.mapArray(valueDim, function (val) {
		return val;
	});
	var indices = [];
	var isAscending = sort === 'ascending';

	for (var i = 0, len = data.count(); i < len; i++) {
		indices[i] = i;
	} // Add custom sortable function & none sortable opetion by "options.sort"

	if (isFunction(sort)) {
		indices.sort(sort);
	} else if (sort !== 'none') {
		indices.sort(function (a, b) {
			return isAscending ? valueArr[a] - valueArr[b] : valueArr[b] - valueArr[a];
		});
	}

	return indices;
}

function labelLayout(data) {
	var seriesModel = data.hostModel;
	var orient = seriesModel.get('orient');
	data.each(function (idx) {
		var itemModel = data.getItemModel(idx);
		var labelModel = itemModel.getModel('label');
		var labelPosition = labelModel.get('position');
		var labelLineModel = itemModel.getModel('labelLine');
		var layout = data.getItemLayout(idx);
		var points = layout.points;
		var isLabelInside = labelPosition === 'inner' || labelPosition === 'inside' || labelPosition === 'center' || labelPosition === 'insideLeft' || labelPosition === 'insideRight';
		var textAlign;
		var textX;
		var textY;
		var linePoints;

		if (isLabelInside) {
			if (labelPosition === 'insideLeft') {
				textX = (points[0][0] + points[3][0]) / 2 + 5;
				textY = (points[0][1] + points[3][1]) / 2;
				textAlign = 'left';
			} else if (labelPosition === 'insideRight') {
				textX = (points[1][0] + points[2][0]) / 2 - 5;
				textY = (points[1][1] + points[2][1]) / 2;
				textAlign = 'right';
			} else {
				textX = (points[0][0] + points[1][0] + points[2][0] + points[3][0]) / 4;
				textY = (points[0][1] + points[1][1] + points[2][1] + points[3][1]) / 4;
				textAlign = 'center';
			}

			linePoints = [[textX, textY], [textX, textY]];
		} else {
			var x1 = void 0;
			var y1 = void 0;
			var x2 = void 0;
			var y2 = void 0;
			var labelLineLen = labelLineModel.get('length');

			if (process.env.NODE_ENV !== 'production') {
				if (orient === 'vertical' && ['top', 'bottom'].indexOf(labelPosition) > -1) {
					labelPosition = 'left';
					console.warn('Position error: Funnel chart on vertical orient dose not support top and bottom.');
				}

				if (orient === 'horizontal' && ['left', 'right'].indexOf(labelPosition) > -1) {
					labelPosition = 'bottom';
					console.warn('Position error: Funnel chart on horizontal orient dose not support left and right.');
				}
			}

			if (labelPosition === 'left') {
				// Left side
				x1 = (points[3][0] + points[0][0]) / 2;
				y1 = (points[3][1] + points[0][1]) / 2;
				x2 = x1 - labelLineLen;
				textX = x2 - 5;
				textAlign = 'right';
			} else if (labelPosition === 'right') {
				// Right side
				x1 = (points[1][0] + points[2][0]) / 2;
				y1 = (points[1][1] + points[2][1]) / 2;
				x2 = x1 + labelLineLen;
				textX = x2 + 5;
				textAlign = 'left';
			} else if (labelPosition === 'top') {
				// Top side
				x1 = (points[3][0] + points[0][0]) / 2;
				y1 = (points[3][1] + points[0][1]) / 2;
				y2 = y1 - labelLineLen;
				textY = y2 - 5;
				textAlign = 'center';
			} else if (labelPosition === 'bottom') {
				// Bottom side
				x1 = (points[1][0] + points[2][0]) / 2;
				y1 = (points[1][1] + points[2][1]) / 2;
				y2 = y1 + labelLineLen;
				textY = y2 + 5;
				textAlign = 'center';
			} else if (labelPosition === 'rightTop') {
				// RightTop side
				x1 = orient === 'horizontal' ? points[3][0] : points[1][0];
				y1 = orient === 'horizontal' ? points[3][1] : points[1][1];

				if (orient === 'horizontal') {
					y2 = y1 - labelLineLen;
					textY = y2 - 5;
					textAlign = 'center';
				} else {
					x2 = x1 + labelLineLen;
					textX = x2 + 5;
					textAlign = 'top';
				}
			} else if (labelPosition === 'rightBottom') {
				// RightBottom side
				x1 = points[2][0];
				y1 = points[2][1];

				if (orient === 'horizontal') {
					y2 = y1 + labelLineLen;
					textY = y2 + 5;
					textAlign = 'center';
				} else {
					x2 = x1 + labelLineLen;
					textX = x2 + 5;
					textAlign = 'bottom';
				}
			} else if (labelPosition === 'leftTop') {
				// LeftTop side
				x1 = points[0][0];
				y1 = orient === 'horizontal' ? points[0][1] : points[1][1];

				if (orient === 'horizontal') {
					y2 = y1 - labelLineLen;
					textY = y2 - 5;
					textAlign = 'center';
				} else {
					x2 = x1 - labelLineLen;
					textX = x2 - 5;
					textAlign = 'right';
				}
			} else if (labelPosition === 'leftBottom') {
				// LeftBottom side
				x1 = orient === 'horizontal' ? points[1][0] : points[3][0];
				y1 = orient === 'horizontal' ? points[1][1] : points[2][1];

				if (orient === 'horizontal') {
					y2 = y1 + labelLineLen;
					textY = y2 + 5;
					textAlign = 'center';
				} else {
					x2 = x1 - labelLineLen;
					textX = x2 - 5;
					textAlign = 'right';
				}
			} else {
				// Right side or Bottom side
				x1 = (points[1][0] + points[2][0]) / 2;
				y1 = (points[1][1] + points[2][1]) / 2;

				if (orient === 'horizontal') {
					y2 = y1 + labelLineLen;
					textY = y2 + 5;
					textAlign = 'center';
				} else {
					x2 = x1 + labelLineLen;
					textX = x2 + 5;
					textAlign = 'left';
				}
			}

			if (orient === 'horizontal') {
				x2 = x1;
				textX = x2;
			} else {
				y2 = y1;
				textY = y2;
			}

			linePoints = [[x1, y1], [x2, y2]];
		}

		layout.label = {
			linePoints: linePoints,
			x: textX,
			y: textY,
			verticalAlign: 'middle',
			textAlign: textAlign,
			inside: isLabelInside
		};
	});
}

export default function funnelLayout(ecModel, api) {
	ecModel.eachSeriesByType('funnel', function (seriesModel) {
		var data = seriesModel.getData();
		var valueDim = data.mapDimension('value');
		var sort = seriesModel.get('sort');
		var viewRect = getViewRect(seriesModel, api);
		var orient = seriesModel.get('orient');
		var viewWidth = viewRect.width;
		var viewHeight = viewRect.height;
		var indices = getSortedIndices(data, sort);
		var x = viewRect.x;
		var y = viewRect.y;
		var sizeExtent = orient === 'horizontal' ? [parsePercent(seriesModel.get('minSize'), viewHeight), parsePercent(seriesModel.get('maxSize'), viewHeight)] : [parsePercent(seriesModel.get('minSize'), viewWidth), parsePercent(seriesModel.get('maxSize'), viewWidth)];
		var dataExtent = data.getDataExtent(valueDim);
		var min = seriesModel.get('min');
		var max = seriesModel.get('max');

		if (min == null) {
			min = Math.min(dataExtent[0], 0);
		}

		if (max == null) {
			max = dataExtent[1];
		}

		var funnelAlign = seriesModel.get('funnelAlign');
		var gap = seriesModel.get('gap');
		var viewSize = orient === 'horizontal' ? viewWidth : viewHeight;
		var itemSize = (viewSize - gap * (data.count() - 1)) / data.count();

		var getLinePoints = function (idx, offset) {
			// End point index is data.count() and we assign it 0
			if (orient === 'horizontal') {
				var val_1 = data.get(valueDim, idx) || 0;
				var itemHeight = linearMap(val_1, [min, max], sizeExtent, true);
				var y0 = void 0;

				switch (funnelAlign) {
				case 'top':
					y0 = y;
					break;

				case 'center':
					y0 = y + (viewHeight - itemHeight) / 2;
					break;

				case 'bottom':
					y0 = y + (viewHeight - itemHeight);
					break;
				}

				return [[offset, y0], [offset, y0 + itemHeight]];
			}

			var val = data.get(valueDim, idx) || 0;
			var itemWidth = linearMap(val, [min, max], sizeExtent, true);
			var x0;

			switch (funnelAlign) {
			case 'left':
				x0 = x;
				break;

			case 'center':
				x0 = x + (viewWidth - itemWidth) / 2;
				break;

			case 'right':
				x0 = x + viewWidth - itemWidth;
				break;
			}

			return [[x0, offset], [x0 + itemWidth, offset]];
		};

		if (sort === 'ascending') {
			// From bottom to top
			itemSize = -itemSize;
			gap = -gap;

			if (orient === 'horizontal') {
				x += viewWidth;
			} else {
				y += viewHeight;
			}

			indices = indices.reverse();
		}

		for (var i = 0; i < indices.length; i++) {
			var idx = indices[i];
			var nextIdx = indices[i + 1];
			var itemModel = data.getItemModel(idx);

			if (orient === 'horizontal') {
				var width = itemModel.get(['itemStyle', 'width']);

				if (width == null) {
					width = itemSize;
				} else {
					width = parsePercent(width, viewWidth);

					if (sort === 'ascending') {
						width = -width;
					}
				}

				var start = getLinePoints(idx, x);
				var end = getLinePoints(nextIdx, x + width);
				x += width + gap;
				data.setItemLayout(idx, {
					points: start.concat(end.slice().reverse())
				});
			} else {
				var height = itemModel.get(['itemStyle', 'height']);

				if (height == null) {
					height = itemSize;
				} else {
					height = parsePercent(height, viewHeight);

					if (sort === 'ascending') {
						height = -height;
					}
				}

				var start = getLinePoints(idx, y);
				var end = getLinePoints(nextIdx, y + height);
				y += height + gap;
				data.setItemLayout(idx, {
					points: start.concat(end.slice().reverse())
				});
			}
		}

		labelLayout(data);
	});
}